#include "CPUTimeCounter.h"
#include "Misc/Assert.h"
#include "Output/Console.h"

CCPUTimeCounter *CCPUTimeCounter::Get()
{
    static CCPUTimeCounter TimeCounter;
    return &TimeCounter;
}

void CCPUTimeCounter::BeginTimeCount()
{
    if(State!=EState::Idle)
    {
        return;
    }


    TimeCountResult=STimeCountResult();

    Semaphore.release((int32_t)ETimeCountThread::Max-1);

    State=EState::TimeCounting;
    
}

CCPUTimeCounter::STimeCountResult CCPUTimeCounter::EndTimeCount()
{
    GASSERT(State==EState::TimeCounting,U"并不处于统计状态，无法结束");

    State=EState::Finishing;

    //移除逻辑线程的最后一个帧，因为这个帧是不完整的
    TimeCountResult.ThreadTimes[(int32_t)ETimeCountThread::LogicThread].Frames.Pop();

    //等待非逻辑线程结束统计
    for(int32_t i=1;i<(int32_t)ETimeCountThread::Max;++i)
    {
        Semaphore.acquire();
    }
    State=EState::Idle;

    return TimeCountResult;
}

CCPUTimeCounter::EState CCPUTimeCounter::GetState() const
{
    return State;
}

void CCPUTimeCounter::PrintTimeCountResult(
    const STimeCountResult &InTimeCountResult
    ,int64_t InMaxFrameCount
    )
{
    WH::PrintLine(U"统计CPU 占用时间");

    //打印每个线程的统计结果
    int64_t MaxFrameCount=InMaxFrameCount>=0?InMaxFrameCount:InTimeCountResult.ThreadTimes[0].Frames.Num();
    MaxFrameCount=std::min(MaxFrameCount,(int64_t)InTimeCountResult.ThreadTimes[1].Frames.Num());

   
    for(int32_t i=0;i<(int32_t)ETimeCountThread::Max;++i)
    {
        const SThreadTime& ThreadTime = InTimeCountResult.ThreadTimes[i];

        WH::PrintLine(U"线程{}",GetThreadName((ETimeCountThread)i));
        WH::PrintLine(U"统计帧数:{}",ThreadTime.Frames.Num());
        for(int32_t j=0;j<MaxFrameCount;++j)
        {
            const std::shared_ptr<SCodeBlockTime>& Frame = ThreadTime.Frames[j];
            WH::PrintLine(U"第{}帧 总时间:{}ms",j,Frame->TotalTime);
            PrintCodeBlockTime(Frame,0);
        }
    }

    //找到最长帧
    int32_t LongestFrame[uint64_t(ETimeCountThread::Max)]={0};
    float LongestFrameTime[uint64_t(ETimeCountThread::Max)]={0};
    for(int32_t i=0;i<(int32_t)ETimeCountThread::Max;++i)
    {
        const SThreadTime& ThreadTime = InTimeCountResult.ThreadTimes[i];
        for(int32_t j=0;j<InTimeCountResult.ThreadTimes[i].Frames.Num();++j)
        {
            const std::shared_ptr<SCodeBlockTime>& Frame = ThreadTime.Frames[j];
            if(Frame->TotalTime>LongestFrameTime[i])
            {
                LongestFrameTime[i]=Frame->TotalTime;
                LongestFrame[i]=j;
            }
        }
    }

    //打印最长帧
    for(int32_t i=0;i<(int32_t)ETimeCountThread::Max;++i)
    {
        const SThreadTime& ThreadTime = InTimeCountResult.ThreadTimes[i];
        const std::shared_ptr<SCodeBlockTime>& Frame = ThreadTime.Frames[LongestFrame[i]];
        WH::PrintLine(U"线程{} 最长帧 第{}帧 总时间:{}ms",GetThreadName((ETimeCountThread)i),LongestFrame[i],Frame->TotalTime);
        PrintCodeBlockTime(Frame,0);
    }

}

void CCPUTimeCounter::BeginFrameTimeCount(ETimeCountThread Thread)
{
    if (State!=EState::TimeCounting)
    {
        return;
    }

    if(Thread!=ETimeCountThread::LogicThread)
    {
        Semaphore.acquire();
    }


    SThreadTime& ThreadTime = TimeCountResult.ThreadTimes[uint64_t(Thread)];
    ThreadTime.ThreadID=std::this_thread::get_id();

    std::shared_ptr<SCodeBlockTime> NewFrame = std::make_shared<SCodeBlockTime>();
    ThreadTime.Frames.Add(NewFrame);
    
    NewFrame->FieldName = CString(U"Frame")+CString(ThreadTime.Frames.Num()-1);
    NewFrame->Count = 1;
    NewFrame->TotalTime = 0;
    NewFrame->StartTicks = std::chrono::steady_clock::now();
}

void CCPUTimeCounter::EndFrameTimeCount(ETimeCountThread Thread)
{
    if (State==EState::Idle)
    {
        //不在统计状态，不参与统计
        return;
    }

    SThreadTime& ThreadTime = TimeCountResult.ThreadTimes[uint64_t(Thread)];

    if(ThreadTime.Frames.Empty())
    {
        //没有执行BeginFrameTimeCount，这一帧不参与统计
        return;
    }

    std::shared_ptr<SCodeBlockTime>& Frame = ThreadTime.Frames.Last();
    //转换成单位为毫秒的浮点数
    Frame->TotalTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - Frame->StartTicks).count() *0.001;

    if(Thread!=ETimeCountThread::LogicThread)
    {
        Semaphore.release();
    }

}

void CCPUTimeCounter::BeginCodeBlockTimeCount(const CString &InFieldName)
{
    if (State!=EState::TimeCounting)
    {
        return;
    }

    //找到当前线程
    ETimeCountThread Thread=ETimeCountThread::Max;
    for(int32_t i=0;i<(int32_t)ETimeCountThread::Max;++i)
    {   
        if(TimeCountResult.ThreadTimes[i].ThreadID==std::this_thread::get_id())
        {
            Thread= (ETimeCountThread)i;
        }
    }

    if(Thread==ETimeCountThread::Max)
    {
        //不在指定的线程中,不参与统计
        return;
    }

    SThreadTime& ThreadTime = TimeCountResult.ThreadTimes[uint64_t(Thread)];
    std::shared_ptr<SCodeBlockTime>& LastFrame = ThreadTime.Frames.Last();
    
    std::shared_ptr<SCodeBlockTime> ParentBlock;
    if(ThreadTime.CodeBlockStack.empty())
    {
        ParentBlock = LastFrame;
    }
    else
    {
        ParentBlock = ThreadTime.CodeBlockStack.top();
    }

    //查找相同名字的代码块
    std::shared_ptr<SCodeBlockTime> CodeBlock;
    if(ParentBlock->Children.Contains(InFieldName))
    {
        CodeBlock = ParentBlock->Children[InFieldName];
    }
    else
    {
        CodeBlock = std::make_shared<SCodeBlockTime>();
        CodeBlock->FieldName = InFieldName;
        CodeBlock->TotalTime = 0;
        ParentBlock->Children.Add(InFieldName, CodeBlock);
    }
    CodeBlock->Count ++;
    CodeBlock->StartTicks = std::chrono::steady_clock::now();

    ThreadTime.CodeBlockStack.push(CodeBlock);
}

void CCPUTimeCounter::EndCodeBlockTimeCount()
{
    if (State!=EState::TimeCounting)
    {
        return;
    }

    //找到当前线程
    ETimeCountThread Thread=ETimeCountThread::Max;
    for(int32_t i=0;i<(int32_t)ETimeCountThread::Max;++i)
    {   
        if(TimeCountResult.ThreadTimes[i].ThreadID==std::this_thread::get_id())
        {
            Thread= (ETimeCountThread)i;
        }
    }

    if(Thread==ETimeCountThread::Max)
    {
        //不在指定的线程中,不参与统计
        return;
    }

    SThreadTime& ThreadTime = TimeCountResult.ThreadTimes[uint64_t(Thread)];
    if(ThreadTime.Frames.Empty())
    {
        //没有执行BeginFrameTimeCount，这一帧不参与统计
        return;
    }
    std::shared_ptr<SCodeBlockTime>& LastFrame = ThreadTime.Frames.Last();
    
    std::shared_ptr<SCodeBlockTime> CodeBlock=ThreadTime.CodeBlockStack.top();
    ThreadTime.CodeBlockStack.pop();

    CodeBlock->TotalTime += std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - CodeBlock->StartTicks).count() *0.001;

}

CString CCPUTimeCounter::GetThreadName(ETimeCountThread Thread)
{
    switch (Thread)
    {
        case ETimeCountThread::LogicThread:
            return U"逻辑线程";
        case ETimeCountThread::PreRenderThread:
            return U"预渲染线程";
        case ETimeCountThread::RenderThread:
            return U"渲染线程";
        default:
            return U"未知线程";
    }
}

void CCPUTimeCounter::PrintCodeBlockTime(std::shared_ptr<SCodeBlockTime> InCodeBlockTime, int32_t Level)
{
    for(int32_t i=0;i<Level;++i)
    {
        WH::Print(U"  ");
    }
    WH::PrintLine(U"{} 调用次数:{} 总时间:{}ms",InCodeBlockTime->FieldName,InCodeBlockTime->Count,InCodeBlockTime->TotalTime);
    for(auto& Child : InCodeBlockTime->Children)
    {
        PrintCodeBlockTime(Child.Value,Level+1);
    }
}
